package com.inmaytide.website.utils.office;

import com.inmaytide.website.utils.office.annotation.ExcelEntity;
import com.inmaytide.website.utils.office.annotation.ExcelField;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.List;

/**
 * @author Moss
 * @version 1.0.0
 * @since May 26, 2016
 */
public class ExcelUtils extends AbstractExcelUtils {

    private boolean autoNumber = true;
    private boolean autoHeader = true;
    private String templetePath;
    private int startRow;
    private int startCol;
    private CellStyle headerStyle;

    public ExcelUtils(Class<? extends java.io.Serializable> entityClass) {
        super(entityClass);
        if (getEntityClass().isAnnotationPresent(ExcelEntity.class)) {
            ExcelEntity excelEntity = getEntityClass().getAnnotation(ExcelEntity.class);
            this.autoNumber = excelEntity.autoNumber();
            this.autoHeader = excelEntity.autoHeader();
        }
        this.startRow = autoHeader ? 1 : 0;
        this.startCol = autoNumber ? 1 : 0;
    }

    public ExcelUtils(Class<? extends java.io.Serializable> entityClass, int startRow, int startCol) {
        super(entityClass);
        this.autoNumber = false;
        this.autoHeader = false;
        this.startRow = startRow;
        this.startCol = startCol;
    }

    public ExcelUtils(Class<? extends java.io.Serializable> entityClass, String templetePath, int startRow, int startCol) {
        this(entityClass, startRow, startCol);
        this.templetePath = templetePath;
    }

    public void write(OutputStream os, List<? extends java.io.Serializable> elements) throws IOException {
        try (Workbook book = createWorkbook()) {
            setDefaultStyles(book);
            Sheet sheet = StringUtils.isNotEmpty(templetePath) ? book.getSheetAt(0) : book.createSheet();
            if (autoHeader) {
                autoHeader(sheet, getColumnFields());
            }
            addContent(sheet, getColumnFields(), elements);
            book.write(os);
            os.flush();
            os.close();
        }
    }

    public void addContent(Sheet sheet, List<Field> fields, List<? extends java.io.Serializable> elements) {
        for (int i = 0; i < elements.size(); i++) {
            Object element = elements.get(i);
            final Row row = sheet.createRow(startRow++);
            if (autoNumber) {
                setCellValue(row.createCell(0), i + 1);
            }
            fields.forEach(f -> {
                ExcelField annotation = f.getAnnotation(ExcelField.class);
                Cell cell = row.createCell(annotation.columnIndex() + startCol);
                try {
                    setCellValue(cell, FieldUtils.readField(f, element));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    }

    private Workbook createWorkbook() {
        if (StringUtils.isNotEmpty(templetePath)) {
            try {
                FileInputStream fis = new FileInputStream(templetePath);
                return WorkbookFactory.create(fis);
            } catch (EncryptedDocumentException | InvalidFormatException | IOException e) {
                throw new RuntimeException(e);
            }
        } else {
            return new HSSFWorkbook();
        }
    }

    private void autoHeader(Sheet sheet, List<Field> fields) {
        Row row = sheet.createRow(0);
        if (autoNumber) {
            Cell cell = row.createCell(0);
            cell.setCellValue("序号");
            cell.setCellStyle(headerStyle);
        }
        fields.forEach(f -> {
            ExcelField annotation = f.getAnnotation(ExcelField.class);
            Cell cell = row.createCell(autoNumber ? annotation.columnIndex() + startCol : annotation.columnIndex());
            cell.setCellStyle(headerStyle);
            cell.setCellValue(annotation.header());
        });
    }

    private void setDefaultStyles(Workbook book) {
        headerStyle = book.createCellStyle();
        headerStyle.setAlignment(CellStyle.ALIGN_CENTER);
        Font font = book.createFont();
        font.setBold(true);
        headerStyle.setFont(font);
    }

}
